open Gencode.ClangExec;;

let rec iprint_list_helper nl f = function
  |[] -> ""
  |s::t -> if (t!=[]) then (f s) ^ "," ^ nl ^ (iprint_list_helper nl f t) else (f s)

let iprint_list nl lst f = "[" ^ (iprint_list_helper nl lst f) ^ "]"

let iprint_value = function
  |BoolV true -> "BoolV True"
  |BoolV false -> "BoolV False" 
  |NatV v -> "NatV " ^ Big_int.string_of_big_int v

let iprint_type = function
  |BoolT ->"BoolT"
  |NatT ->"NatT"

let iprint_expr = function
   Evar v -> "Evar " ^ v
  |Eimm v -> "Eimm " ^ "("^iprint_value v ^")"

let iprint_bexpr = function
  |Bex e -> "Bex (" ^ iprint_expr e ^ ")"
  |Beq (e1,e2) -> "Beq (" ^ iprint_expr e1 ^ ") (" ^ iprint_expr e2 ^")"
  |Bneq (e1,e2) -> "Bneq (" ^ iprint_expr e1 ^ ") (" ^ iprint_expr e2 ^")"

let iprint_wc = function
  |Weq (s,e) -> "Weq " ^ s ^ " (" ^ iprint_expr e ^ ")"
  |Wneq (s,e) -> "Wneq " ^ s ^ " (" ^ iprint_expr e ^ ")"

let print_lb = function
  |None -> "None"
  |Some x -> "(Some " ^ x ^ ")"

let rec iprint_stmt nl indent = function
    Cnone lb-> nl ^ indent ^ "(Cnone " ^ print_lb lb ^ ")"
  | Cseq (lb,s1,s2) -> nl ^ indent ^ " (Cseq " ^ print_lb lb ^ " " ^ iprint_stmt nl indent s1 ^ " " ^ iprint_stmt nl indent s2 ^ ")"
  | Casg (lb,n, e) -> nl ^ indent ^ "(Casg " ^ print_lb lb ^ " " ^ n ^ " (" ^ iprint_expr e ^ "))"
  | Cif (lb,be, s1, s2) -> nl ^ indent ^ "(Cif " ^ print_lb lb ^ " (" ^ iprint_bexpr be ^ ") then " ^ iprint_stmt "\n" (indent^"  ") s1 ^ "\n"^ indent ^ "else " ^ iprint_stmt "\n" (indent^"  ") s2 ^ "\n" ^ indent ^ "fi"
  | Cwhile (lb,be, s) -> nl ^ indent ^ "(Cwhile " ^ print_lb lb ^ " (" ^ iprint_bexpr be ^ ") " ^ iprint_stmt "\n" (indent^"  ") s ^ "\n" ^ indent ^ ")"
  | Cread (lb,n, m) -> nl ^ indent ^ "(Cread " ^ print_lb lb ^ " " ^ n ^ " " ^ m ^ ")"
  | Cwrite (lb,m, e) -> nl ^ indent ^ "(Cwrite " ^ print_lb lb ^ " " ^ m ^ " (" ^ iprint_expr e ^ "))"
  | Cwait (lb,bes, s) -> nl ^ indent ^ "(Cwait " ^ print_lb lb ^ " (" ^ (iprint_list " " iprint_wc bes) ^ ") " ^ iprint_stmt "\n" (indent^"  ") s ^ "\n" ^ indent ^ ")"

let iprint_vd = function
  | Vdecl(nm,tp) ->  "(Vdecl " ^ nm ^ " " ^ iprint_type tp ^ ")"
;;

let rec iprint_proc = function
   |Proc (Phdr (name,svds,vds),bd) ->
      "(Proc (Phdr " ^ name ^ " " ^ (iprint_list " " iprint_vd svds) ^ " " ^ (iprint_list " " iprint_vd vds) ^ ")" ^ (iprint_stmt "\n" "  " bd) ^ "\n)\n"
;;

let iprint_full_program prog = iprint_list "\n" iprint_proc prog
